package cn.edu.jxust.core.infrastructure.util;

import cn.edu.jxust.core.infrastructure.OneNetConst;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author QiuKangming
 * @version 1.0
 * @description Aqi 计算工具类
 * @since 2020/07/15 23:03
 */

@SuppressWarnings("all")
public class AqiUtils {

    /**空气质量分指数*/
    private static final List<Integer> AQIList= Arrays.asList(0,50,100,150,200,300,400,500);
    /**SO2 1小时 平均(ug/m3)*/
    private static final List<Integer> SO2HOURList= Arrays.asList(0,150,500,650,800);
    /**SO2 24小时 平均*/
    private static final List<Integer> SO2DAYList= Arrays.asList(0,50,150,475,800,1600,2100,2620);
    /**NO2 1小时 平均(ug/m3)*/
    private static final List<Integer> NO2HOURList= Arrays.asList(0,100,200,700,1200,2340,3090,3840);
    /**NO2 24小时 平均*/
    private static final List<Integer> NO2DAYList= Arrays.asList(0,40,80,180,280,565,750,940);
    /**PM10 24小时 平均*/
    private static final List<Integer> PM10DAYList= Arrays.asList(0,50,150,250,350,420,500,600);
    /**CO 1小时 平均(mg/m3)*/
    private static final List<Integer> COHOURList= Arrays.asList(0,5,10,35,60,90,120,150);
    /**CO 24小时 平均(mg/m3)*/
    private static final List<Integer> CODAYList= Arrays.asList(0,2,4,14,24,36,48,60);
    /**O3 小时 平均(ug/m3)*/
    private static final List<Integer> O3HOURList= Arrays.asList(0,160,200,300,400,800,1000,1200);
    /**O3 8小时滑动 平均(ug/m3)*/
    private static final List<Integer> O3_8HList= Arrays.asList(0,100,160,215,265,800);
    /**PM25 24小时平均(ug/m3)*/
    private static final List<Integer> PM25DAYList= Arrays.asList(0,35,75,115,150,250,350,500);

    private static final List<String> listPollute = Arrays.asList("SO2", "NO2", "O3", "PM10", "PM2.5", "CO");

    public static final String HAQI="H"; //小时aqi标识
    public static final String DAQI="D"; //日aqi标识

    /**
     * 空气质量指数AQI的计算:供AQI计算调用, 获取首要污染物
     * 注意事项:
     * 6参值顺序固定
     * @param SO2 so2
     * @param NO2 no2
     * @param O3 o3
     * @param PM10 pm10
     * @param PM25 pm2.5
     * @param CO co
     * @param aqiType aqi类型
     * @return Aqi (AQI值和首要污染物)
     */
    public static Aqi getAQIByParam(Double SO2, Double NO2, Double O3, Double PM10, Double PM25, Double CO, String aqiType){
        List<Integer> list = new ArrayList<>();
        Aqi aqi = new Aqi();
        if (null != SO2 && SO2 > 0 && SO2 <= 800){ // 二氧化硫（SO2 ）1 小时平均浓度值高于 800 μg/m3 的，不再进行其空气质量分指数计算，二氧化硫（SO2 ）空气质量分指数按 24 小时平均浓度计算的分指数报告。
            list.add(getIAQI(OneNetConst.SO2, SO2, aqiType));
        }else {
            list.add(null);
        }
        if(null!=NO2 && NO2>0 && NO2<=3840){
            list.add(getIAQI(OneNetConst.NO2,NO2,aqiType));
        }else {
            list.add(null);
        }
        if(null!=O3 && O3>0 && O3<=1200){
            list.add(getIAQI(OneNetConst.O3,O3,aqiType));
        }else {
            list.add(null);
        }
        if(null!=PM10 && PM10>0 && PM10<=600){//24小时
            list.add(getIAQI(OneNetConst.PM10,PM10,aqiType));
        }else {
            list.add(null);
        }
        if(null!=PM25 && PM25>0 && PM25<=500){//24小时
            list.add(getIAQI(OneNetConst.PM25,PM25,aqiType));
        }else {
            list.add(null);
        }
        if(null!=CO && CO>0 && CO<=150){
            list.add(getIAQI(OneNetConst.CO,CO,aqiType));
        }else {
            list.add(null);
        }
        // list长度可能小于listPollute长度；
        // 首要污染物为，空气质量指数大于 50 时，空气质量分指数最大的空气污染物。
        // 多种首要污染物
        if(list.size() > 0){
            Integer maxAqiValue = null;
            for (Integer aqiValue : list) { // 全为null（返回null），部分为null，全不为null
                if(aqiValue != null) {
                    if(maxAqiValue == null) {
                        maxAqiValue = aqiValue;
                    }else {
                        if( aqiValue> maxAqiValue) {
                            maxAqiValue = aqiValue;
                        }
                    }
                }
            }

            if(maxAqiValue != null && maxAqiValue > 50) {
                StringBuilder pollutesJoint = null;
                for (int i=0; i<list.size(); i++) {
                    Integer aqiValue = list.get(i);
                    if(maxAqiValue.equals(aqiValue)) { // 不会空指针异常
                        if(pollutesJoint == null) {
                            pollutesJoint = new StringBuilder(listPollute.get(i));
                        }else {
                            pollutesJoint.append(",").append(listPollute.get(i));
                        }
                    }
                }
                aqi.setAqi(maxAqiValue);
                aqi.setName(null == pollutesJoint ? null : pollutesJoint.toString());
            }else{
                aqi.setAqi(maxAqiValue);
                aqi.setName("--");
            }

        }
        return aqi;
    }

    /**
     * 分指数计算: 计算每种气体的IAQI值
     * @param param 气体名称
     * @param paramValue 气体的浓度值
     * @param type 小时数据还是日数据
     * @return Integer
     */
    public static Integer getIAQI(String param,Double paramValue,String type){
        int IAQI=-99;
        switch (param){
            case OneNetConst.SO2:
                if(HAQI.equals(type)){
                    IAQI= getIAQIValue(SO2HOURList,paramValue);
                    break;
                }else{
                    IAQI= getIAQIValue(SO2DAYList,paramValue);
                    break;
                }
            case OneNetConst.NO2:
                if(HAQI.equals(type)){
                    IAQI= getIAQIValue(NO2HOURList,paramValue);
                    break;
                }else{
                    IAQI= getIAQIValue(NO2DAYList,paramValue);
                    break;
                }
            case OneNetConst.O3:
                if(HAQI.equals(type)){
                    IAQI= getIAQIValue(O3HOURList,paramValue);
                    break;
                }else{
                    IAQI= getIAQIValue(O3_8HList,paramValue);
                    break;
                }
            case OneNetConst.PM10:
                IAQI= getIAQIValue(PM10DAYList,paramValue);
                break;
            case OneNetConst.PM25:
                IAQI= getIAQIValue(PM25DAYList,paramValue);
                break;
            case OneNetConst.CO:
                if(HAQI.equals(type)){
                    IAQI= getIAQIValue(COHOURList,paramValue);
                    break;
                }else{
                    IAQI= getIAQIValue(CODAYList,paramValue);
                    break;
                }
        }
        return IAQI;
    }

    /**
     * 获取IAQI的值
     * @param list list
     * @param paramValue 值
     * @return Integer
     */
    private static Integer getIAQIValue(List<?> list, Double paramValue){
        int IAQI;
        int BPL=0;//低位值
        int BPH=0;//高位值
        int BPHIndex=0;
        int IAQIH;//BPH对应的空气质量分指数
        int IAQIL;//BPL对应的空气质量分指数
        for(int i=0;i<list.size();i++){
            if((Integer)list.get(i)>(paramValue.intValue())){
                BPH=(Integer)list.get(i);
                BPL=(Integer)list.get(i-1);
                BPHIndex=i;
                break;
            }
        }
        IAQIH=AQIList.get(BPHIndex);
        IAQIL=AQIList.get(BPHIndex-1);
        double AQI=(((double) ((IAQIH-IAQIL)*100)/(BPH-BPL))*0.01)*(paramValue-BPL)+IAQIL;
        IAQI= (int)Math.ceil(AQI);
        return IAQI;
    }

    /**
     * 根据 aqi值获取aqi的等级
     * @param aqi aqi值
     * @return int 等级
     */
    public static int getAqiLevel(int aqi) {
        int aqiLevel;
        if (aqi <= 50) {
            aqiLevel = Const.AQI_LEVEL_1;
        } else if (aqi <= 100) {
            aqiLevel = Const.AQI_LEVEL_2;
        } else if (aqi <= 150) {
            aqiLevel = Const.AQI_LEVEL_3;
        } else if (aqi <= 200) {
            aqiLevel = Const.AQI_LEVEL_4;
        } else if (aqi <= 300) {
            aqiLevel = Const.AQI_LEVEL_5;
        } else {
            aqiLevel = Const.AQI_LEVEL_6;
        }
        return aqiLevel;
    }

    /**
     * 返回 aqi 对应的等级字符串
     * @param aqiLevel aqi等级
     * @return string
     */
    public static String getAqiLevelStr(int aqiLevel) {
        if (aqiLevel == Const.AQI_LEVEL_1) {
            return "优";
        } else if (aqiLevel == Const.AQI_LEVEL_2) {
            return "良";
        } else if (aqiLevel == Const.AQI_LEVEL_3) {
            return "轻度污染";
        } else if (aqiLevel == Const.AQI_LEVEL_4) {
            return "中度污染";
        } else if (aqiLevel == Const.AQI_LEVEL_5) {
            return "重度污染";
        } else if (aqiLevel == Const.AQI_LEVEL_6) {
            return "严重污染";
        }
        return "数据错误";
    }

    /**
     * 检查检测的数据的浓度是否超过阈值: 返回 true ， 没超过阈值， 返回false 有问题
     * @param airName 气体名称
     * @param concentration 气体浓度， 计算出来的
     * @param type aqi类型， 小时数居或者日数据
     * @return boolean
     */
    public static boolean checkAirConcentration(String airName, double concentration, String type){

        switch (airName){
            case OneNetConst.SO2:
                if(HAQI.equals(type)){
                    return concentration <= 800;
                }else{
                    return concentration <= 2620;
                }
            case OneNetConst.NO2:
                if(HAQI.equals(type)){
                    return concentration <= 3840;
                }else{
                    return concentration <= 940;
                }
            case OneNetConst.O3:
                if(HAQI.equals(type)){
                    return concentration <= 1200;
                }else{
                    return concentration <= 800;
                }
            case OneNetConst.PM10:
                return concentration <= 600;
            case OneNetConst.PM25:
                return concentration <= 500;
            case OneNetConst.CO:
                if(HAQI.equals(type)){
                    return concentration <= 150;
                }else{
                    return concentration <= 60;
                }
            default:
                return false;
        }

    }

    /**
     * 获取气体的标准值
     * @param airName 气体名称
     * @param type 类行
     * @return double
     */
    public static double getAirStandaredCon(String airName, String type){

        switch (airName){
            case OneNetConst.SO2:
                if(HAQI.equals(type)){
                    return 800;
                }else{
                    return 2620;
                }
            case OneNetConst.NO2:
                if(HAQI.equals(type)){
                    return 3840;
                }else{
                    return 940;
                }
            case OneNetConst.O3:
                if(HAQI.equals(type)){
                    return 1200;
                }else{
                    return 800;
                }
            case OneNetConst.PM10:
                return 600;
            case OneNetConst.PM25:
                return 500;
            case OneNetConst.CO:
                if(HAQI.equals(type)){
                    return 150;
                }else{
                    return 60;
                }
            default:
                return 0;
        }

    }

}
